import 'package:event_bus/event_bus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:gim_plugin_example/pages/pg_login/pg_login.dart';
import 'package:gim_plugin_example/utils/logger_utils.dart';

class AppNav extends RouterDelegate<String> with PopNavigatorRouterDelegateMixin<String>, ChangeNotifier {
  final _defaultPage = PgLogin();
  final _stack = <String>[];
  final Map<String, Widget> _routeMap = {};

  static AppNav of(BuildContext context) {
    final delegate = Router.of(context).routerDelegate;
    assert(delegate is AppNav, 'Delegate type must match');
    return delegate as AppNav;
  }

  @override
  GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

  @override
  String? get currentConfiguration => _stack.isNotEmpty ? _stack.last : null;

  List<String> get stack => List.unmodifiable(_stack);

  bool inPage<T>() {
    loggerInfo(_routeMap[_stack[_stack.length - 1]]);
    return _routeMap[_stack[_stack.length - 1]] is T;
  }

  int _ts = 0;

  void push(Widget page, {String? key}) {
    int now = DateTime.now().millisecondsSinceEpoch;
    if (now - _ts < 300) {
      _ts = now;
      return;
    }
    _ts = now;
    if (key == null || key == '') {
      key = '${page.hashCode}';
    }
    _stack.add(key);
    _routeMap[key] = page;
    navEvt.evtBus.fire(EvtNavChange(page, _stack.length));
    notifyListeners();
  }

  void replaceAll(Widget page) {
    String key = '${page.hashCode}';
    _stack.clear();
    _routeMap.clear();
    _stack.add(key);
    _routeMap[key] = page;
    navEvt.evtBus.fire(EvtNavChange(page, _stack.length));
    notifyListeners();
  }

  @override
  Future<void> setInitialRoutePath(String configuration) {
    return setNewRoutePath(configuration);
  }

  @override
  Future<void> setNewRoutePath(String configuration) async {
    _stack
      ..clear()
      ..add(configuration);
    _routeMap.clear();
    _routeMap[configuration] = _defaultPage;
    return SynchronousFuture<void>(null);
  }

  bool _onPopPage(Route<dynamic> route, dynamic result) {
    if (_stack.isNotEmpty) {
      String routeName = _stack.last;
      Widget? pushWidget = _routeMap[routeName];
      _stack.remove(routeName);
      _routeMap.remove(routeName);
      navEvt.evtBus.fire(EvtNavChange(_routeMap[_stack.last]!, _stack.length));
      loggerDebug(_stack.length);
      notifyListeners();
    }
    return route.didPop(result);
  }

  @override
  Widget build(BuildContext context) {
    List<Page> pages = [];
    for (String route in _stack) {
      Widget wgt = _routeMap[route]!;
      pages.add(MaterialPage(child: wgt, key: ValueKey('${wgt.hashCode}')));
    }
    return MediaQuery(
        data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
        child: Navigator(
          key: navigatorKey,
          onPopPage: _onPopPage,
          pages: pages,
        ));
  }
}

class AppRouteParser extends RouteInformationParser<String> {
  @override
  Future<String> parseRouteInformation(RouteInformation routeInformation) {
    return SynchronousFuture(routeInformation.location!);
  }

  @override
  RouteInformation restoreRouteInformation(String configuration) {
    return RouteInformation(location: configuration);
  }
}

class EvtNavChange {
  final Widget currPage;
  final int stackSize;

  EvtNavChange(this.currPage, this.stackSize);
}

class _NavEvt {
  final evtBus = EventBus();

  _NavEvt() {
    evtBus.on<EvtNavChange>().listen((event) {
      if (_evtNavChangePool.isEmpty) return;
      for (Function fn in _evtNavChangePool) {
        fn(event);
      }
    });
  }

  final Set<Function> _evtNavChangePool = {};

  addEvt(Function cb) {
    _evtNavChangePool.add(cb);
  }

  delEvt(Function cb) {
    _evtNavChangePool.remove(cb);
  }
}

_NavEvt navEvt = _NavEvt();
